/* Target-machine dependent code for the AMD 29000
- Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995
+ Free Software Foundation, Inc.
Contributed by Cygnus Support. Written by Jim Kingdon.
-This file is part of GDB.
+ 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 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.
+ 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. */
+ 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., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "gdbcore.h"
static CORE_ADDR rstack_high_address = UINT_MAX;
+
+/* Should call_function allocate stack space for a struct return? */
+/* On the a29k objects over 16 words require the caller to allocate space. */
+int
+a29k_use_struct_convention (int gcc_p, struct type *type)
+{
+ return (TYPE_LENGTH (type) > 16 * 4);
+}
+
+
/* Structure to hold cached info about function prologues. */
+
struct prologue_info
{
CORE_ADDR pc; /* First addr after fn prologue */
unsigned rsize, msize; /* register stack frame size, mem stack ditto */
- unsigned mfp_used : 1; /* memory frame pointer used */
- unsigned rsize_valid : 1; /* Validity bits for the above */
- unsigned msize_valid : 1;
- unsigned mfp_valid : 1;
+ unsigned mfp_used:1; /* memory frame pointer used */
+ unsigned rsize_valid:1; /* Validity bits for the above */
+ unsigned msize_valid:1;
+ unsigned mfp_valid:1;
};
/* Examine the prologue of a function which starts at PC. Return
If MFP_USED is non-NULL, *MFP_USED is set to nonzero if a memory
frame pointer is being used. */
+
CORE_ADDR
-examine_prologue (pc, rsize, msize, mfp_used)
- CORE_ADDR pc;
- unsigned *msize;
- unsigned *rsize;
- int *mfp_used;
+examine_prologue (CORE_ADDR pc, unsigned *rsize, unsigned *msize, int *mfp_used)
{
long insn;
CORE_ADDR p = pc;
struct prologue_info *mi = 0;
if (msymbol != NULL)
- mi = (struct prologue_info *) msymbol -> info;
+ mi = (struct prologue_info *) msymbol->info;
if (mi != 0)
{
*msize = 0;
if (mfp_used != NULL)
*mfp_used = 0;
-
+
/* Prologue must start with subtracting a constant from gr1.
Normally this is sub gr1,gr1,<rsize * 4>. */
insn = read_memory_integer (p, 4);
if ((insn & 0xffffff00) != 0x25010100)
{
/* If the frame is large, instead of a single instruction it
- might be a pair of instructions:
- const <reg>, <rsize * 4>
- sub gr1,gr1,<reg>
- */
+ might be a pair of instructions:
+ const <reg>, <rsize * 4>
+ sub gr1,gr1,<reg>
+ */
int reg;
/* Possible value for rsize. */
unsigned int rsize0;
-
+
if ((insn & 0xff000000) != 0x03000000)
{
p = pc;
}
p += 4;
- /* Next instruction must be asgeu V_SPILL,gr1,rab.
+ /* Next instruction ought to 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.
+ * If this insn is missing, we just keep going; Metaware R2.3u compiler
+ * generates prologue that intermixes initializations and puts the asgeu
+ * way down.
*/
insn = read_memory_integer (p, 4);
- if ((insn & 0xff00ffff) != (0x5e000100|RAB_HW_REGNUM))
+ if ((insn & 0xff00ffff) == (0x5e000100 | RAB_HW_REGNUM))
{
- p = pc;
- goto done;
+ p += 4;
}
- p += 4;
/* Next instruction usually sets the frame pointer (lr1) by adding
<size * 4> from gr1. However, this can (and high C does) be
else
{
/* However, for large frames it can be
- const <reg>, <size *4>
- add lr1,gr1,<reg>
- */
+ const <reg>, <size *4>
+ add lr1,gr1,<reg>
+ */
int reg;
CORE_ADDR q;
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) == (0x15800000|(MSP_HW_REGNUM<<8))) /* add */
- || ((insn & 0xff80ffff) == (0x81800000|(MSP_HW_REGNUM<<8)))) /* sll */
+ if (((insn & 0xff80ffff) == (0x15800000 | (MSP_HW_REGNUM << 8))) /* add */
+ || ((insn & 0xff80ffff) == (0x81800000 | (MSP_HW_REGNUM << 8)))) /* sll */
{
p += 4;
if (mfp_used != NULL)
Normally this is just
sub msp,msp,<msize>
- */
+ */
insn = read_memory_integer (p, 4);
- if ((insn & 0xffffff00) ==
- (0x25000000|(MSP_HW_REGNUM<<16)|(MSP_HW_REGNUM<<8)))
+ if ((insn & 0xffffff00) ==
+ (0x25000000 | (MSP_HW_REGNUM << 16) | (MSP_HW_REGNUM << 8)))
{
p += 4;
- if (msize != NULL)
+ if (msize != NULL)
*msize = insn & 0xff;
}
else
{
/* For large frames, instead of a single instruction it might
- be
+ be
- const <reg>, <msize>
- consth <reg>, <msize> ; optional
- sub msp,msp,<reg>
- */
+ const <reg>, <msize>
+ consth <reg>, <msize> ; optional
+ sub msp,msp,<reg>
+ */
int reg;
unsigned msize0;
CORE_ADDR q = p;
insn = read_memory_integer (q, 4);
}
/* Check for sub msp,msp,<reg>. */
- if ((insn & 0xffffff00) ==
- (0x24000000|(MSP_HW_REGNUM<<16)|(MSP_HW_REGNUM<<8))
+ if ((insn & 0xffffff00) ==
+ (0x24000000 | (MSP_HW_REGNUM << 16) | (MSP_HW_REGNUM << 8))
&& (insn & 0xff) == reg)
{
p = q + 4;
}
}
- done:
+ /* Next instruction might 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.
+ * Metaware R2.3u compiler
+ * generates prologue that intermixes initializations and puts the asgeu
+ * way down after everything else.
+ */
+ insn = read_memory_integer (p, 4);
+ if ((insn & 0xff00ffff) == (0x5e000100 | RAB_HW_REGNUM))
+ {
+ p += 4;
+ }
+
+done:
if (msymbol != NULL)
{
if (mi == 0)
{
/* Add a new cache entry. */
- mi = (struct prologue_info *)xmalloc (sizeof (struct prologue_info));
- msymbol -> info = (char *)mi;
+ mi = (struct prologue_info *) xmalloc (sizeof (struct prologue_info));
+ msymbol->info = (char *) mi;
mi->rsize_valid = 0;
mi->msize_valid = 0;
mi->mfp_valid = 0;
to reach some "real" code. */
CORE_ADDR
-skip_prologue (pc)
- CORE_ADDR pc;
+a29k_skip_prologue (CORE_ADDR pc)
{
- return examine_prologue (pc, (unsigned *)NULL, (unsigned *)NULL,
- (int *)NULL);
+ return examine_prologue (pc, NULL, NULL, 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
* 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;
+
+static int /* 0/1 - failure/success of finding the tag word */
+examine_tag (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 & TAGWORD_ZERO_MASK) != 0) /* Not a tag word */
return 0;
- if (tag1 & (1<<23)) /* A two word tag */
+ if (tag1 & (1 << 23)) /* A two word tag */
{
- tag2 = read_memory_integer (p+4, 4);
- if (msize)
- *msize = tag2;
+ tag2 = read_memory_integer (p - 4, 4);
+ if (msize)
+ *msize = tag2 * 2;
}
- else /* A one word tag */
+ else
+ /* A one word tag */
{
- if (msize)
- *msize = tag1 & 0x7ff;
+ if (msize)
+ *msize = tag1 & 0x7ff;
}
if (is_trans)
- *is_trans = ((tag1 & (1<<21)) ? 1 : 0);
+ *is_trans = ((tag1 & (1 << 21)) ? 1 : 0);
+ /* Note that this includes the frame pointer and the return address
+ register, so the actual number of registers of arguments is two less.
+ argcount can be zero, however, sometimes, for strange assembler
+ routines. */
if (argcount)
*argcount = (tag1 >> 16) & 0x1f;
if (mfp_used)
- *mfp_used = ((tag1 & (1<<22)) ? 1 : 0);
- return(1);
+ *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
because we need to know it to get the other stuff. See the diagram
of stacks and the frame cache in tm-a29k.h for more detail. */
+
static void
-init_frame_info (innermost_frame, fci)
- int innermost_frame;
- struct frame_info *fci;
+init_frame_info (int innermost_frame, struct frame_info *frame)
{
CORE_ADDR p;
long insn;
int mfp_used, trans;
struct symbol *func;
- p = fci->pc;
+ p = frame->pc;
if (innermost_frame)
- fci->frame = read_register (GR1_REGNUM);
+ frame->frame = read_register (GR1_REGNUM);
else
- fci->frame = fci->next->frame + fci->next->rsize;
-
-#if CALL_DUMMY_LOCATION == ON_STACK
+ frame->frame = frame->next->frame + frame->next->rsize;
+
+#if 0 /* CALL_DUMMY_LOCATION == ON_STACK */
This wont work;
#else
if (PC_IN_CALL_DUMMY (p, 0, 0))
#endif
{
- fci->rsize = DUMMY_FRAME_RSIZE;
+ frame->rsize = DUMMY_FRAME_RSIZE;
/* This doesn't matter since we never try to get locals or args
- from a dummy frame. */
- fci->msize = 0;
+ from a dummy frame. */
+ frame->msize = 0;
/* 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);
+ frame->saved_msp =
+ read_register_stack_integer (frame->frame + DUMMY_FRAME_RSIZE - 4, 4);
+ frame->flags |= (TRANSPARENT_FRAME | MFP_USED);
return;
}
-
+
func = find_pc_function (p);
if (func != NULL)
p = BLOCK_START (SYMBOL_BLOCK_VALUE (func));
else
{
/* Search backward to find the trace-back tag. However,
- do not trace back beyond the start of the text segment
- (just as a sanity check to avoid going into never-never land). */
+ do not trace back beyond the start of the text segment
+ (just as a sanity check to avoid going into never-never land). */
+#if 1
while (p >= text_start
- && ((insn = read_memory_integer (p, 4)) & TAGWORD_ZERO_MASK) != 0)
+ && ((insn = read_memory_integer (p, 4)) & TAGWORD_ZERO_MASK) != 0)
p -= 4;
-
+#else /* 0 */
+ char pat[4] =
+ {0, 0, 0, 0};
+ char mask[4];
+ char insn_raw[4];
+ store_unsigned_integer (mask, 4, TAGWORD_ZERO_MASK);
+ /* Enable this once target_search is enabled and tested. */
+ target_search (4, pat, mask, p, -4, text_start, p + 1, &p, &insn_raw);
+ insn = extract_unsigned_integer (insn_raw, 4);
+#endif /* 0 */
+
if (p < text_start)
{
/* Couldn't find the trace-back tag.
Something strange is going on. */
- fci->saved_msp = 0;
- fci->rsize = 0;
- fci->msize = 0;
- fci->flags = TRANSPARENT;
+ frame->saved_msp = 0;
+ frame->rsize = 0;
+ frame->msize = 0;
+ frame->flags = TRANSPARENT_FRAME;
return;
}
else
after the trace-back tag. */
p += 4;
}
+
/* 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;
+ 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. */
+
+ if (examine_tag (p - 4, &trans, (int *) NULL, &msize, &mfp_used)) /* Found good tag */
+ examine_prologue (p, &rsize, 0, 0);
+ else /* No tag try prologue */
+ examine_prologue (p, &rsize, &msize, &mfp_used);
+
+ frame->rsize = rsize;
+ frame->msize = msize;
+ frame->flags = 0;
if (mfp_used)
- fci->flags |= MFP_USED;
+ frame->flags |= MFP_USED;
if (trans)
- fci->flags |= TRANSPARENT;
+ frame->flags |= TRANSPARENT_FRAME;
if (innermost_frame)
{
- fci->saved_msp = read_register (MSP_REGNUM) + msize;
+ frame->saved_msp = read_register (MSP_REGNUM) + msize;
}
else
{
if (mfp_used)
- fci->saved_msp =
- read_register_stack_integer (fci->frame + rsize - 4, 4);
+ frame->saved_msp =
+ read_register_stack_integer (frame->frame + rsize - 4, 4);
else
- fci->saved_msp = fci->next->saved_msp + msize;
+ frame->saved_msp = frame->next->saved_msp + msize;
}
}
void
-init_extra_frame_info (fci)
- struct frame_info *fci;
+init_extra_frame_info (struct frame_info *frame)
{
- if (fci->next == 0)
+ if (frame->next == 0)
/* Assume innermost frame. May produce strange results for "info frame"
but there isn't any way to tell the difference. */
- init_frame_info (1, fci);
- else {
- /* We're in get_prev_frame_info.
+ init_frame_info (1, frame);
+ else
+ {
+ /* We're in get_prev_frame.
Take care of everything in init_frame_pc. */
;
}
}
void
-init_frame_pc (fromleaf, fci)
- int fromleaf;
- struct frame_info *fci;
+init_frame_pc (int fromleaf, struct frame_info *frame)
{
- fci->pc = (fromleaf ? SAVED_PC_AFTER_CALL (fci->next) :
- fci->next ? FRAME_SAVED_PC (fci->next) : read_pc ());
- init_frame_info (fromleaf, fci);
+ frame->pc = (fromleaf ? SAVED_PC_AFTER_CALL (frame->next) :
+ frame->next ? FRAME_SAVED_PC (frame->next) : read_pc ());
+ init_frame_info (fromleaf, frame);
}
\f
/* Local variables (i.e. LOC_LOCAL) are on the memory stack, with their
saved_msp (gcc). */
CORE_ADDR
-frame_locals_address (fi)
- struct frame_info *fi;
+frame_locals_address (struct frame_info *fi)
{
- if (fi->flags & MFP_USED)
+ if (fi->flags & MFP_USED)
return fi->saved_msp;
else
return fi->saved_msp - fi->msize;
on where it came from. The contents written into MYADDR are in
target format. */
void
-read_register_stack (memaddr, myaddr, actual_mem_addr, lval)
- CORE_ADDR memaddr;
- char *myaddr;
- CORE_ADDR *actual_mem_addr;
- enum lval_type *lval;
+read_register_stack (CORE_ADDR memaddr, char *myaddr,
+ CORE_ADDR *actual_mem_addr, enum lval_type *lval)
{
long rfb = read_register (RFB_REGNUM);
long rsp = read_register (RSP_REGNUM);
/* If we don't do this 'info register' stops in the middle. */
- if (memaddr >= rstack_high_address)
+ if (memaddr >= rstack_high_address)
{
/* a bogus value */
- char val[] = {~0, ~0, ~0, ~0};
+ static char val[] =
+ {~0, ~0, ~0, ~0};
/* It's in a local register, but off the end of the stack. */
int regnum = (memaddr - rsp) / 4 + LR0_REGNUM;
if (myaddr != NULL)
/* Provide bogusness */
memcpy (myaddr, val, 4);
}
- supply_register(regnum, val); /* More bogusness */
+ supply_register (regnum, val); /* More bogusness */
if (lval != NULL)
*lval = lval_register;
if (actual_mem_addr != NULL)
else
{
/* It's in the memory portion of the register stack. */
- if (myaddr != NULL)
+ if (myaddr != NULL)
read_memory (memaddr, myaddr, 4);
if (lval != NULL)
*lval = lval_memory;
/* Analogous to read_memory_integer
except the length is understood to be 4. */
long
-read_register_stack_integer (memaddr, len)
- CORE_ADDR memaddr;
- int len;
+read_register_stack_integer (CORE_ADDR memaddr, int len)
{
- long buf;
- read_register_stack (memaddr, &buf, NULL, NULL);
- SWAP_TARGET_AND_HOST (&buf, 4);
- return buf;
+ char buf[4];
+ read_register_stack (memaddr, buf, NULL, NULL);
+ return extract_signed_integer (buf, 4);
}
/* Copy 4 bytes from GDB memory at MYADDR into inferior memory
at MEMADDR and put the actual address written into in
*ACTUAL_MEM_ADDR. */
static void
-write_register_stack (memaddr, myaddr, actual_mem_addr)
- CORE_ADDR memaddr;
- char *myaddr;
- CORE_ADDR *actual_mem_addr;
+write_register_stack (CORE_ADDR memaddr, char *myaddr,
+ CORE_ADDR *actual_mem_addr)
{
long rfb = read_register (RFB_REGNUM);
long rsp = read_register (RSP_REGNUM);
/* If we don't do this 'info register' stops in the middle. */
- if (memaddr >= rstack_high_address)
+ 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 = 0;
+ *actual_mem_addr = 0;
}
else if (memaddr < rfb)
{
if (regnum < LR0_REGNUM || regnum > LR0_REGNUM + 127)
error ("Attempt to read register stack out of range.");
if (myaddr != NULL)
- write_register (regnum, *(long *)myaddr);
+ write_register (regnum, *(long *) myaddr);
if (actual_mem_addr != NULL)
*actual_mem_addr = 0;
}
otherwise it was fetched from a register.
The argument RAW_BUFFER must point to aligned memory. */
+
void
-get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lvalp)
- char *raw_buffer;
- int *optimized;
- CORE_ADDR *addrp;
- FRAME frame;
- int regnum;
- enum lval_type *lvalp;
+a29k_get_saved_register (char *raw_buffer, int *optimized, CORE_ADDR *addrp,
+ struct frame_info *frame, int regnum,
+ enum lval_type *lvalp)
{
struct frame_info *fi;
CORE_ADDR addr;
enum lval_type lval;
+ if (!target_has_registers)
+ error ("No registers.");
+
+ /* Probably now redundant with the target_has_registers check. */
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;
{
if (raw_buffer != NULL)
{
- *(CORE_ADDR *)raw_buffer = fi->frame;
- /* Put it back in target byte order. */
- SWAP_TARGET_AND_HOST (raw_buffer, sizeof (CORE_ADDR));
+ store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), frame->frame);
}
if (lvalp != NULL)
*lvalp = not_lval;
return;
}
- else if (regnum == PC_REGNUM)
+ else if (regnum == PC_REGNUM && frame->next != NULL)
{
if (raw_buffer != NULL)
{
- *(CORE_ADDR *)raw_buffer = fi->pc;
- /* Put it back in target byte order. */
- SWAP_TARGET_AND_HOST (raw_buffer, sizeof (CORE_ADDR));
+ store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), frame->pc);
}
/* Not sure we have to do this. */
{
if (raw_buffer != NULL)
{
- if (fi->next != NULL)
+ if (frame->next != NULL)
{
- *(CORE_ADDR *)raw_buffer = fi->next->saved_msp;
- /* Put it back in target byte order. */
- SWAP_TARGET_AND_HOST (raw_buffer, sizeof (CORE_ADDR));
+ store_address (raw_buffer, REGISTER_RAW_SIZE (regnum),
+ frame->next->saved_msp);
}
else
read_register_gen (MSP_REGNUM, raw_buffer);
else if (regnum < LR0_REGNUM || regnum >= LR0_REGNUM + 128)
{
/* These registers are not saved over procedure calls,
- so just print out the current values. */
+ so just print out the current values. */
if (raw_buffer != NULL)
read_register_gen (regnum, raw_buffer);
if (lvalp != NULL)
*addrp = REGISTER_BYTE (regnum);
return;
}
-
- addr = fi->frame + (regnum - LR0_REGNUM) * 4;
+
+ addr = frame->frame + (regnum - LR0_REGNUM) * 4;
if (raw_buffer != NULL)
read_register_stack (addr, raw_buffer, &addr, &lval);
if (lvalp != NULL)
restoring all saved registers. */
void
-pop_frame ()
+pop_frame (void)
{
- FRAME frame = get_current_frame ();
- struct frame_info *fi = get_frame_info (frame);
- CORE_ADDR rfb = read_register (RFB_REGNUM);
- CORE_ADDR gr1 = fi->frame + fi->rsize;
- CORE_ADDR lr1;
+ struct frame_info *frame = get_current_frame ();
+ CORE_ADDR rfb = read_register (RFB_REGNUM);
+ CORE_ADDR gr1 = frame->frame + frame->rsize;
+ CORE_ADDR lr1;
+ CORE_ADDR original_lr0;
+ int must_fix_lr0 = 0;
int i;
/* If popping a dummy frame, need to restore registers. */
if (PC_IN_CALL_DUMMY (read_register (PC_REGNUM),
read_register (SP_REGNUM),
- FRAME_FP (fi)))
+ FRAME_FP (frame)))
{
- int lrnum = LR0_REGNUM + DUMMY_ARG/4;
+ int lrnum = LR0_REGNUM + DUMMY_ARG / 4;
for (i = 0; i < DUMMY_SAVE_SR128; ++i)
- write_register (SR_REGNUM (i + 128),read_register (lrnum++));
+ 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++));
+ write_register (SR_REGNUM (i + 160), read_register (lrnum++));
for (i = 0; i < DUMMY_SAVE_GREGS; ++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 PCs and prepare to restore LR0. */
+ write_register (PC_REGNUM, read_register (lrnum++));
+ write_register (NPC_REGNUM, read_register (lrnum++));
+ write_register (PC2_REGNUM, read_register (lrnum++));
+ original_lr0 = read_register (lrnum++);
+ must_fix_lr0 = 1;
}
/* Restore the memory stack pointer. */
- write_register (MSP_REGNUM, fi->saved_msp);
- /* Restore the register stack pointer. */
+ write_register (MSP_REGNUM, frame->saved_msp);
+ /* Restore the register stack pointer. */
write_register (GR1_REGNUM, gr1);
- /* Check whether we need to fill registers. */
- lr1 = read_register (LR0_REGNUM + 1);
- if (lr1 > rfb)
- {
- /* Fill. */
+
+ /* If we popped a dummy frame, restore lr0 now that gr1 has been restored. */
+ if (must_fix_lr0)
+ write_register (LR0_REGNUM, original_lr0);
+
+ /* Check whether we need to fill registers. */
+ lr1 = read_register (LR0_REGNUM + 1);
+ if (lr1 > rfb)
+ {
+ /* Fill. */
int num_bytes = lr1 - rfb;
- int i;
- long word;
- write_register (RAB_REGNUM, read_register (RAB_REGNUM) + num_bytes);
- write_register (RFB_REGNUM, lr1);
- for (i = 0; i < num_bytes; i += 4)
- {
+ int i;
+ long word;
+
+ write_register (RAB_REGNUM, read_register (RAB_REGNUM) + num_bytes);
+ write_register (RFB_REGNUM, lr1);
+ for (i = 0; i < num_bytes; i += 4)
+ {
/* Note: word is in host byte order. */
- word = read_memory_integer (rfb + i, 4);
- write_register (LR0_REGNUM + ((rfb - gr1) % 0x80) + i / 4, word);
- }
+ word = read_memory_integer (rfb + i, 4);
+ write_register (LR0_REGNUM + ((rfb - gr1) % 0x80) + i / 4, word);
+ }
}
- flush_cached_frames ();
- set_current_frame (create_new_frame (0, read_pc()));
+ flush_cached_frames ();
}
/* Push an empty stack frame, to record the current PC, etc. */
-void
-push_dummy_frame ()
+void
+push_dummy_frame (void)
{
long w;
CORE_ADDR rab, gr1;
CORE_ADDR msp = read_register (MSP_REGNUM);
- int lrnum, i, saved_lr0;
-
+ int lrnum, i;
+ CORE_ADDR original_lr0;
+
+ /* Read original lr0 before changing gr1. This order isn't really needed
+ since GDB happens to have a snapshot of all the regs and doesn't toss
+ it when gr1 is changed. But it's The Right Thing To Do. */
+ original_lr0 = read_register (LR0_REGNUM);
- /* Allocate the new frame. */
+ /* Allocate the new frame. */
gr1 = read_register (GR1_REGNUM) - DUMMY_FRAME_RSIZE;
write_register (GR1_REGNUM, gr1);
+#ifdef VXWORKS_TARGET
+ /* We force re-reading all registers to get the new local registers set
+ after gr1 has been modified. This fix is due to the lack of single
+ register read/write operation in the RPC interface between VxGDB and
+ VxWorks. This really must be changed ! */
+
+ vx_read_register (-1);
+
+#endif /* VXWORK_TARGET */
+
rab = read_register (RAB_REGNUM);
if (gr1 < rab)
{
write_register (MSP_REGNUM, msp - 16 * 4);
/* Save registers. */
- lrnum = LR0_REGNUM + DUMMY_ARG/4;
+ lrnum = LR0_REGNUM + DUMMY_ARG / 4;
for (i = 0; i < DUMMY_SAVE_SR128; ++i)
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 (lrnum++, read_register (RETURN_REGNUM + i));
- /* Save the PCs. */
+ /* Save the PCs and LR0. */
write_register (lrnum++, read_register (PC_REGNUM));
- write_register (lrnum, read_register (NPC_REGNUM));
+ write_register (lrnum++, read_register (NPC_REGNUM));
+ write_register (lrnum++, read_register (PC2_REGNUM));
+
+ /* Why are we saving LR0? What would clobber it? (the dummy frame should
+ be below it on the register stack, no?). */
+ write_register (lrnum++, original_lr0);
}
+
+/*
+ This routine takes three arguments and makes the cached frames look
+ as if these arguments defined a frame on the cache. This allows the
+ rest of `info frame' to extract the important arguments without much
+ difficulty. Since an individual frame on the 29K is determined by
+ three values (FP, PC, and MSP), we really need all three to do a
+ good job. */
+
+struct frame_info *
+setup_arbitrary_frame (int argc, CORE_ADDR *argv)
+{
+ struct frame_info *frame;
+
+ if (argc != 3)
+ error ("AMD 29k frame specifications require three arguments: rsp pc msp");
+
+ frame = create_new_frame (argv[0], argv[1]);
+
+ if (!frame)
+ internal_error ("create_new_frame returned invalid frame id");
+
+ /* Creating a new frame munges the `frame' value from the current
+ GR1, so we restore it again here. FIXME, untangle all this
+ 29K frame stuff... */
+ frame->frame = argv[0];
+
+ /* Our MSP is in argv[2]. It'd be intelligent if we could just
+ save this value in the FRAME. But the way it's set up (FIXME),
+ we must save our caller's MSP. We compute that by adding our
+ memory stack frame size to our MSP. */
+ frame->saved_msp = argv[2] + frame->msize;
+
+ return frame;
+}
+
+int
+gdb_print_insn_a29k (bfd_vma memaddr, disassemble_info *info)
+{
+ if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+ return print_insn_big_a29k (memaddr, info);
+ else
+ return print_insn_little_a29k (memaddr, info);
+}
+
+enum a29k_processor_types processor_type = a29k_unknown;
+
void
-_initialize_29k()
+a29k_get_processor_type (void)
+{
+ unsigned int cfg_reg = (unsigned int) read_register (CFG_REGNUM);
+
+ /* Most of these don't have freeze mode. */
+ processor_type = a29k_no_freeze_mode;
+
+ switch ((cfg_reg >> 28) & 0xf)
+ {
+ case 0:
+ fprintf_filtered (gdb_stderr, "Remote debugging an Am29000");
+ break;
+ case 1:
+ fprintf_filtered (gdb_stderr, "Remote debugging an Am29005");
+ break;
+ case 2:
+ fprintf_filtered (gdb_stderr, "Remote debugging an Am29050");
+ processor_type = a29k_freeze_mode;
+ break;
+ case 3:
+ fprintf_filtered (gdb_stderr, "Remote debugging an Am29035");
+ break;
+ case 4:
+ fprintf_filtered (gdb_stderr, "Remote debugging an Am29030");
+ break;
+ case 5:
+ fprintf_filtered (gdb_stderr, "Remote debugging an Am2920*");
+ break;
+ case 6:
+ fprintf_filtered (gdb_stderr, "Remote debugging an Am2924*");
+ break;
+ case 7:
+ fprintf_filtered (gdb_stderr, "Remote debugging an Am29040");
+ break;
+ default:
+ fprintf_filtered (gdb_stderr, "Remote debugging an unknown Am29k\n");
+ /* Don't bother to print the revision. */
+ return;
+ }
+ fprintf_filtered (gdb_stderr, " revision %c\n", 'A' + ((cfg_reg >> 24) & 0x0f));
+}
+
+#ifdef GET_LONGJMP_TARGET
+/* Figure out where the longjmp will land. We expect that we have just entered
+ longjmp and haven't yet setup the stack frame, so the args are still in the
+ output regs. lr2 (LR2_REGNUM) points at the jmp_buf structure from which we
+ extract the pc (JB_PC) that we will land at. The pc is copied into ADDR.
+ This routine returns true on success */
+
+int
+get_longjmp_target (CORE_ADDR *pc)
+{
+ CORE_ADDR jb_addr;
+ char buf[sizeof (CORE_ADDR)];
+
+ jb_addr = read_register (LR2_REGNUM);
+
+ if (target_read_memory (jb_addr + JB_PC * JB_ELEMENT_SIZE, (char *) buf,
+ sizeof (CORE_ADDR)))
+ return 0;
+
+ *pc = extract_address ((PTR) buf, sizeof (CORE_ADDR));
+ return 1;
+}
+#endif /* GET_LONGJMP_TARGET */
+
+void
+_initialize_a29k_tdep (void)
{
extern CORE_ADDR text_end;
+ tm_print_insn = gdb_print_insn_a29k;
+
/* 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,
+ (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),
/* FIXME, there should be a way to make a CORE_ADDR variable settable. */
add_show_from_set
(add_set_cmd ("call_scratch_address", class_support, var_uinteger,
- (char *)&text_end,
-"Set address in memory where small amounts of RAM can be used\n\
+ (char *) &text_end,
+ "Set address in memory where small amounts of RAM can be used\n\
when making function calls into the inferior.", &setlist),
&showlist);
}