* arc-tdep.c: #include "gdbcmd.h".

(codestream_seek): Pass CORE_ADDR.
	(arc_cpu_type, tmp_arc_cpu_type, arc_cpu_type_table): New globals.
	(debug_pipeline_p): Likewise.
	(X_...): Instruction field access macros.
	(BUILD_INSN): Define.
	(codestream_tell): Allow for stream elements > 1 byte.
	(codestream_fill): Likewise.
	(setup_prologue_scan): New function.
	(arc_get_frame_setup): Call it.  Update to current spec
	regarding prologues.  Use BUILD_INSN.
	(skip_prologue): New argument `frameless_p'.  Use BUILD_INSN.
	(arc_frame_saved_pc): New function.
	(frame_find_saved_regs): Use BUILD_INSN.
	(get_insn_type, single_step): New functions.
	(one_stepped): New global.
	(arc_set_cpu_type_command, arc_show_cpu_type_command): New functions.
	(arc_set_cpu_type): New function.
	(_initialize_arc_tdep): Define new `set' commands `cpu',
	`displaypipeline', and `debugpipeline'.
	* remote-arc.c (break_insn): Add bi-endian support.
	(arc_insert_breakpoint): Likewise.
	(arc_remove_breakpoint): Likewise.
	(switch_command): Delete.
	* arc/tm-arc.h (TARGET_BYTE_ORDER): Delete.
	(TARGET_BYTE_ORDER_SELECTABLE): Define.
	(DEFAULT_ARC_CPU_TYPE): Define.
	(SKIP_PROLOGUE_FRAMELESS_P): Define.
	(BREAKPOINT): Delete.
	(BIG_BREAKPOINT, LITTLE_BREAKPOINT): Define.
	(DECR_PC_AFTER_BREAK): Change to 8.
	(NO_SINGLE_STEP): Define.
	(ARC_PC_TO_REAL_ADDRESS): Define.
	(SAVED_PC_AFTER_CALL): Use it.
	(NUM_REGS, REGISTER_BYTES): Fix.
	(FRAME_SAVED_PC): Call arc_frame_saved_pc.
	(FRAME_LOCALS_ADDRESS): Fix.
This commit is contained in:
David Edelsohn 1995-04-12 15:47:39 +00:00
parent 32513ed10d
commit f0d795faf6
3 changed files with 565 additions and 205 deletions

View File

@ -24,9 +24,62 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "target.h"
#include "floatformat.h"
#include "symtab.h"
#include "gdbcmd.h"
/* Current CPU, set with the "set cpu" command. */
char *arc_cpu_type;
char *tmp_arc_cpu_type;
/* Table of cpu names. */
struct {
char *name;
int value;
} arc_cpu_type_table[] = {
{ "base", bfd_mach_arc_base },
{ "host", bfd_mach_arc_host },
{ "graphics", bfd_mach_arc_graphics },
{ "audio", bfd_mach_arc_audio },
{ NULL, 0 }
};
/* Used by simulator. */
int display_pipeline_p;
int cpu_timer;
/* This one must have the same type as used in the emulator.
It's currently an enum so this should be ok for now. */
int debug_pipeline_p;
#define ARC_CALL_SAVED_REG(r) ((r) >= 16 && (r) < 24)
#define OPMASK 0xf8000000
/* Instruction field accessor macros. */
#define X_OP(i) (((i) >> 27) & 0x1f)
#define X_A(i) (((i) >> 21) & 0x3f)
#define X_B(i) (((i) >> 15) & 0x3f)
#define X_C(i) (((i) >> 9) & 0x3f)
#define X_D(i) ((((i) & 0x1ff) ^ 0x100) - 0x100)
#define X_L(i) (((((i) >> 5) & 0x3ffffc) ^ 0x200000) - 0x200000)
#define X_N(i) (((i) >> 5) & 3)
#define X_Q(i) ((i) & 0x1f)
/* Return non-zero if X is a short immediate data indicator. */
#define SHIMM_P(x) ((x) == 61 || (x) == 63)
/* Return non-zero if X is a "long" (32 bit) immediate data indicator. */
#define LIMM_P(x) ((x) == 62)
/* Build a simple instruction. */
#define BUILD_INSN(op, a, b, c, d) \
((((op) & 31) << 27) \
| (((a) & 63) << 21) \
| (((b) & 63) << 15) \
| (((c) & 63) << 9) \
| ((d) & 511))
/* Codestream stuff. */
static void codestream_read PARAMS ((unsigned int *, int));
static void codestream_seek PARAMS ((int));
static void codestream_seek PARAMS ((CORE_ADDR));
static unsigned int codestream_fill PARAMS ((int));
#define CODESTREAM_BUFSIZ 16
@ -36,22 +89,28 @@ static unsigned int codestream_buf[CODESTREAM_BUFSIZ];
static int codestream_off;
static int codestream_cnt;
#define codestream_tell() (codestream_addr + codestream_off)
#define codestream_peek() (codestream_cnt == 0 ? \
codestream_fill(1): codestream_buf[codestream_off])
#define codestream_get() (codestream_cnt-- == 0 ? \
codestream_fill(0) : codestream_buf[codestream_off++])
#define OPMASK 0xf8000000
#define codestream_tell() \
(codestream_addr + codestream_off * sizeof (codestream_buf[0]))
#define codestream_peek() \
(codestream_cnt == 0 \
? codestream_fill (1) \
: codestream_buf[codestream_off])
#define codestream_get() \
(codestream_cnt-- == 0 \
? codestream_fill (0) \
: codestream_buf[codestream_off++])
static unsigned int
codestream_fill (peek_flag)
int peek_flag;
{
codestream_addr = codestream_next_addr;
codestream_next_addr += CODESTREAM_BUFSIZ;
codestream_next_addr += CODESTREAM_BUFSIZ * sizeof (codestream_buf[0]);
codestream_off = 0;
codestream_cnt = CODESTREAM_BUFSIZ;
read_memory (codestream_addr, (char *) codestream_buf, CODESTREAM_BUFSIZ);
/* FIXME: need to handle byte order differences. */
read_memory (codestream_addr, (char *) codestream_buf,
CODESTREAM_BUFSIZ * sizeof (codestream_buf[0]));
if (peek_flag)
return (codestream_peek());
@ -61,7 +120,7 @@ codestream_fill (peek_flag)
static void
codestream_seek (place)
int place;
CORE_ADDR place;
{
codestream_next_addr = place / CODESTREAM_BUFSIZ;
codestream_next_addr *= CODESTREAM_BUFSIZ;
@ -82,145 +141,171 @@ codestream_read (buf, count)
for (i = 0; i < count; i++)
*p++ = codestream_get ();
}
/* Set up prologue scanning and return the first insn,
not including the "sub sp,sp,32" of a stdarg function. */
/*
* find & return amound a local space allocated, and advance codestream to
* first register push (if any)
* if entry sequence doesn't make sense, return -1, and leave
* codestream pointer random
*/
static long
arc_get_frame_setup (pc)
int pc;
static unsigned int
setup_prologue_scan (pc)
CORE_ADDR pc;
{
unsigned int insn, n;
unsigned int insn;
codestream_seek (pc);
insn = codestream_get ();
if (insn & OPMASK == 0x10000000) /* st fp,[sp] */
{
insn = codestream_get ();
if (insn & OPMASK != 0x10000000) /* st blink,[sp,4] */
{
if (insn & OPMASK != 0x60000000) /* for leaf, no st blink */
return -1;
}
else if (codestream_get () & OPMASK != 0x60000000) /* mov fp,sp */
return (-1);
/* The authority for what appears here is the home-grown ABI. */
/* check for stack adjustment sub sp,nnn,sp */
insn = codestream_peek ();
if (insn & OPMASK == 0x50000000)
{
n = (insn & 0x000001ff );
codestream_get ();
/* First insn may be "sub sp,sp,32" if stdarg fn. */
if (insn == BUILD_INSN (10, SP_REGNUM, SP_REGNUM, SHIMM_REGNUM, 32))
insn = codestream_get ();
/* this sequence is used to get the address of the return
* buffer for a function that returns a structure
*/
insn = codestream_peek ();
if (insn & OPMASK == 0x60000000)
codestream_get ();
return n;
}
else
{
return (0);
}
}
return (-1);
}
/* return pc of first real instruction */
CORE_ADDR
skip_prologue (pc)
int pc;
{
unsigned int insn;
int i;
CORE_ADDR pos;
if (arc_get_frame_setup (pc) < 0)
return (pc);
/* skip over register saves */
for (i = 0; i < 10; i++)
{
insn = codestream_peek ();
if (insn & OPMASK != 0x10000000) /* break if not st inst */
break;
codestream_get ();
}
codestream_seek (pos);
return (codestream_tell ());
}
/* Return number of args passed to a frame.
Can return -1, meaning no way to tell. */
int
frame_num_args (fi)
struct frame_info *fi;
{
#if 1
return -1;
#else
/* This loses because not only might the compiler not be popping the
args right after the function call, it might be popping args from both
this call and a previous one, and we would say there are more args
than there really are. Is it true for ARC */
int retpc;
unsigned char op;
struct frame_info *pfi;
int frameless;
FRAMELESS_FUNCTION_INVOCATION (fi, frameless);
if (frameless)
/* In the absence of a frame pointer, GDB doesn't get correct values
for nameless arguments. Return -1, so it doesn't print any
nameless arguments. */
return -1;
pfi = get_prev_frame_info (fi);
if (pfi == 0)
{
/* Note: this can happen if we are looking at the frame for
main, because FRAME_CHAIN_VALID won't let us go into
start. If we have debugging symbols, that's not really
a big deal; it just means it will only show as many arguments
to main as are declared. */
return -1;
}
else
{
retpc = pfi->pc;
op = read_memory_integer (retpc, 1);
if (op == 0x59)
/* pop %ecx */
return 1;
}
else
{
return 0;
}
}
#endif
return insn;
}
/*
* parse the first few instructions of the function to see
* Find & return amount a local space allocated, and advance codestream to
* first register push (if any).
* If entry sequence doesn't make sense, return -1, and leave
* codestream pointer random.
*/
static long
arc_get_frame_setup (pc)
CORE_ADDR pc;
{
unsigned int insn;
/* Size of frame or -1 if unrecognizable prologue. */
int n = -1;
insn = setup_prologue_scan (pc);
if ((insn & BUILD_INSN (-1, 0, -1, -1, -1)) /* st blink,[sp,4] */
== BUILD_INSN (2, 0, SP_REGNUM, BLINK_REGNUM, 4))
{
insn = codestream_get ();
/* Frame may not be necessary, even though blink is saved.
At least this is something we recognize. */
n = 0;
}
if ((insn & BUILD_INSN (-1, 0, -1, -1, -1)) /* st fp,[sp] */
== BUILD_INSN (2, 0, SP_REGNUM, FP_REGNUM, 0))
{
insn = codestream_get ();
if ((insn & BUILD_INSN (-1, -1, -1, -1, 0))
!= BUILD_INSN (12, FP_REGNUM, SP_REGNUM, SP_REGNUM, 0))
return -1;
/* Check for stack adjustment sub sp,sp,nnn. */
insn = codestream_peek ();
if ((insn & BUILD_INSN (-1, -1, -1, 0, 0))
== BUILD_INSN (10, SP_REGNUM, SP_REGNUM, 0, 0))
{
if (LIMM_P (X_C (insn)))
n = codestream_get ();
else if (SHIMM_P (X_C (insn)))
n = X_D (insn);
else
return -1;
if (n < 0)
return -1;
codestream_get ();
/* This sequence is used to get the address of the return
buffer for a function that returns a structure. */
insn = codestream_peek ();
if (insn & OPMASK == 0x60000000)
codestream_get ();
}
/* Frameless fn. */
else
{
n = 0;
}
}
return n;
}
/* Given a pc value, skip it forward past the function prologue by
disassembling instructions that appear to be a prologue.
If FRAMELESS_P is set, we are only testing to see if the function
is frameless. If it is a frameless function, return PC unchanged.
This allows a quicker answer. */
CORE_ADDR
skip_prologue (pc, frameless_p)
CORE_ADDR pc;
int frameless_p;
{
unsigned int insn;
int i, frame_size;
if ((frame_size = arc_get_frame_setup (pc)) < 0)
return (pc);
if (frameless_p)
return frame_size == 0 ? pc : codestream_tell ();
/* Skip over register saves. */
for (i = 0; i < 8; i++)
{
insn = codestream_peek ();
if ((insn & BUILD_INSN (-1, 0, -1, 0, 0))
!= BUILD_INSN (2, 0, SP_REGNUM, 0, 0))
break; /* not st insn */
if (! ARC_CALL_SAVED_REG (X_C (insn)))
break;
codestream_get ();
}
return codestream_tell ();
}
/* Return the return address for a frame.
This is used to implement FRAME_SAVED_PC.
This is taken from frameless_look_for_prologue. */
CORE_ADDR
arc_frame_saved_pc (frame)
struct frame_info *frame;
{
CORE_ADDR func_start;
unsigned int insn;
func_start = get_pc_function_start (frame->pc) + FUNCTION_START_OFFSET;
if (func_start == 0)
{
/* Best guess. */
return ARC_PC_TO_REAL_ADDRESS (read_memory_integer (FRAME_FP (frame) + 4, 4));
}
/* If the first insn is "st blink,[sp,4]" we can get blink from there.
Otherwise this is a leaf function and we can use blink. Note that
this still allows for the case where a leaf function saves/clobbers/
restores blink. */
insn = setup_prologue_scan (func_start);
if ((insn & BUILD_INSN (-1, 0, -1, -1, -1)) /* st blink,[sp,4] */
!= BUILD_INSN (2, 0, SP_REGNUM, BLINK_REGNUM, 4))
return ARC_PC_TO_REAL_ADDRESS (read_register (BLINK_REGNUM));
else
return ARC_PC_TO_REAL_ADDRESS (read_memory_integer (FRAME_FP (frame) + 4, 4));
}
/*
* Parse the first few instructions of the function to see
* what registers were stored.
*
* The startup sequence can be at the start of the function.
* 'st fp,[sp], st blink,[sp+4], mov fp,sp'
* 'st blink,[sp+4], st fp,[sp], mov fp,sp'
*
* Local space is allocated just below by sub sp,nnn,sp
* Next, the registers used by this function are stored.
* Local space is allocated just below by sub sp,sp,nnn.
* Next, the registers used by this function are stored (as offsets from sp).
*/
void
@ -233,15 +318,13 @@ frame_find_saved_regs (fip, fsrp)
CORE_ADDR dummy_bottom;
CORE_ADDR adr;
int i, regnum, offset;
memset (fsrp, 0, sizeof *fsrp);
/* if frame is the end of a dummy, compute where the
* beginning would be
*/
/* If frame is the end of a dummy, compute where the beginning would be. */
dummy_bottom = fip->frame - 4 - REGISTER_BYTES - CALL_DUMMY_LENGTH;
/* check if the PC is in the stack, in a dummy frame */
/* Check if the PC is in the stack, in a dummy frame. */
if (dummy_bottom <= fip->pc && fip->pc <= fip->frame)
{
/* all regs were saved by push_call_dummy () */
@ -253,23 +336,25 @@ frame_find_saved_regs (fip, fsrp)
}
return;
}
locals = arc_get_frame_setup (get_pc_function_start (fip->pc));
if (locals >= 0)
{
/* Set `adr' to the value of `sp'. */
adr = fip->frame - locals;
for (i = 0; i < 10; i++)
for (i = 0; i < 8; i++)
{
insn = codestream_get ();
if (insn & 0xffff8000 != 0x100d8000)
if ((insn & BUILD_INSN (-1, 0, -1, 0, 0))
!= BUILD_INSN (2, 0, SP_REGNUM, 0, 0))
break;
regnum = (insn & 0x00007c00) >> 9;
offset = (insn << 23) >> 23;
regnum = X_C (insn);
offset = X_D (insn);
fsrp->regs[regnum] = adr + offset;
}
}
fsrp->regs[PC_REGNUM] = fip->frame + 4;
fsrp->regs[FP_REGNUM] = fip->frame;
}
@ -322,7 +407,141 @@ pop_frame ()
write_register (SP_REGNUM, fp + 8);
flush_cached_frames ();
}
/* Simulate single-step. */
typedef enum
{
NORMAL4, /* a normal 4 byte insn */
NORMAL8, /* a normal 8 byte insn */
BRANCH4, /* a 4 byte branch insn, including ones without delay slots */
BRANCH8, /* an 8 byte branch insn, including ones with delay slots */
} insn_type;
/* Return the type of INSN and store in TARGET the destination address of a
branch if this is one. */
/* ??? Need to verify all cases are properly handled. */
static insn_type
get_insn_type (insn, pc, target)
unsigned long insn;
CORE_ADDR pc, *target;
{
unsigned long limm;
switch (insn >> 27)
{
case 0 : case 1 : case 2 : /* load/store insns */
if (LIMM_P (X_A (insn))
|| LIMM_P (X_B (insn))
|| LIMM_P (X_C (insn)))
return NORMAL8;
return NORMAL4;
case 4 : case 5 : case 6 : /* branch insns */
*target = pc + 4 + X_L (insn);
/* ??? It isn't clear that this is always the right answer.
The problem occurs when the next insn is an 8 byte insn. If the
branch is conditional there's no worry as there shouldn't be an 8
byte insn following. The programmer may be cheating if s/he knows
the branch will never be taken, but we don't deal with that.
Note that the programmer is also allowed to play games by putting
an insn with long immediate data in the delay slot and then duplicate
the long immediate data at the branch target. Ugh! */
if (X_N (insn) == 0)
return BRANCH4;
return BRANCH8;
case 7 : /* jump insns */
if (LIMM_P (X_B (insn)))
{
limm = read_memory_integer (pc + 4, 4);
*target = ARC_PC_TO_REAL_ADDRESS (limm);
return BRANCH8;
}
if (SHIMM_P (X_B (insn)))
*target = ARC_PC_TO_REAL_ADDRESS (X_D (insn));
else
*target = ARC_PC_TO_REAL_ADDRESS (read_register (X_B (insn)));
if (X_Q (insn) == 0 && X_N (insn) == 0)
return BRANCH4;
return BRANCH8;
default : /* arithmetic insns, etc. */
if (LIMM_P (X_A (insn))
|| LIMM_P (X_B (insn))
|| LIMM_P (X_C (insn)))
return NORMAL8;
return NORMAL4;
}
}
/* Non-zero if we just simulated a single-step. This is needed because we
cannot remove the breakpoints in the inferior process until after the
`wait' in `wait_for_inferior'. */
int one_stepped;
/* single_step() is called just before we want to resume the inferior, if we
want to single-step it but there is no hardware or kernel single-step
support. We find all the possible targets of the coming instruction and
breakpoint them.
single_step is also called just after the inferior stops. If we had
set up a simulated single-step, we undo our damage. */
void
single_step (ignore)
int ignore; /* sig, but we don't need it */
{
static CORE_ADDR next_pc, target;
static int brktrg_p;
typedef char binsn_quantum[BREAKPOINT_MAX];
static binsn_quantum break_mem[2];
if (!one_stepped)
{
insn_type type;
CORE_ADDR pc;
unsigned long insn;
pc = read_register (PC_REGNUM);
insn = read_memory_integer (pc, 4);
type = get_insn_type (insn, pc, &target);
/* Always set a breakpoint for the insn after the branch. */
next_pc = pc + ((type == NORMAL8 || type == BRANCH8) ? 8 : 4);
target_insert_breakpoint (next_pc, break_mem[0]);
brktrg_p = 0;
if ((type == BRANCH4 || type == BRANCH8)
/* Watch out for branches to the following location.
We just stored a breakpoint there and another call to
target_insert_breakpoint will think the real insn is the
breakpoint we just stored there. */
&& target != next_pc)
{
brktrg_p = 1;
target_insert_breakpoint (target, break_mem[1]);
}
/* We are ready to let it go. */
one_stepped = 1;
}
else
{
/* Remove breakpoints. */
target_remove_breakpoint (next_pc, break_mem[0]);
if (brktrg_p)
target_remove_breakpoint (target, break_mem[1]);
/* Fix the pc. */
stop_pc -= DECR_PC_AFTER_BREAK;
write_pc (stop_pc);
one_stepped = 0;
}
}
#ifdef GET_LONGJMP_TARGET
/* Figure out where the longjmp will land. Slurp the args out of the stack.
We expect the first arg to be a pointer to the jmp_buf structure from which
@ -354,9 +573,113 @@ get_longjmp_target(pc)
return 1;
}
#endif /* GET_LONGJMP_TARGET */
/* Command to set cpu type. */
void
arc_set_cpu_type_command (args, from_tty)
char *args;
int from_tty;
{
int i;
if (tmp_arc_cpu_type == NULL || *tmp_arc_cpu_type == '\0')
{
printf_unfiltered ("The known ARC cpu types are as follows:\n");
for (i = 0; arc_cpu_type_table[i].name != NULL; ++i)
printf_unfiltered ("%s\n", arc_cpu_type_table[i].name);
/* Restore the value. */
tmp_arc_cpu_type = strsave (arc_cpu_type);
return;
}
if (!arc_set_cpu_type (tmp_arc_cpu_type))
{
error ("Unknown cpu type `%s'.", tmp_arc_cpu_type);
/* Restore its value. */
tmp_arc_cpu_type = strsave (arc_cpu_type);
}
}
static void
arc_show_cpu_type_command (args, from_tty)
char *args;
int from_tty;
{
}
/* Modify the actual cpu type.
Result is a boolean indicating success. */
int
arc_set_cpu_type (str)
char *str;
{
int i, j;
if (str == NULL)
return 0;
for (i = 0; arc_cpu_type_table[i].name != NULL; ++i)
{
if (strcasecmp (str, arc_cpu_type_table[i].name) == 0)
{
arc_cpu_type = str;
tm_print_insn = arc_get_disassembler (arc_cpu_type_table[i].value,
TARGET_BYTE_ORDER == BIG_ENDIAN);
return 1;
}
}
return 0;
}
void
_initialize_arc_tdep ()
{
tm_print_insn = arc_get_disassembler (bfd_mach_arc_host);
struct cmd_list_element *c;
c = add_set_cmd ("cpu", class_support, var_string_noescape,
(char *) &tmp_arc_cpu_type,
"Set the type of ARC cpu in use.\n\
This command has two purposes. In a multi-cpu system it lets one\n\
change the cpu being debugged. It also gives one access to\n\
cpu-type-specific registers and recognize cpu-type-specific instructions.\
",
&setlist);
c->function.cfunc = arc_set_cpu_type_command;
c = add_show_from_set (c, &showlist);
c->function.cfunc = arc_show_cpu_type_command;
/* We have to use strsave here because the `set' command frees it before
setting a new value. */
tmp_arc_cpu_type = strsave (DEFAULT_ARC_CPU_TYPE);
arc_set_cpu_type (tmp_arc_cpu_type);
c = add_set_cmd ("displaypipeline", class_support, var_zinteger,
(char *) &display_pipeline_p,
"Set pipeline display (simulator only).\n\
When enabled, the state of the pipeline after each cycle is displayed.",
&setlist);
c = add_show_from_set (c, &showlist);
c = add_set_cmd ("debugpipeline", class_support, var_zinteger,
(char *) &debug_pipeline_p,
"Set pipeline debug display (simulator only).\n\
When enabled, debugging information about the pipeline is displayed.",
&setlist);
c = add_show_from_set (c, &showlist);
c = add_set_cmd ("cputimer", class_support, var_zinteger,
(char *) &cpu_timer,
"Set maximum cycle count (simulator only).\n\
Control will return to gdb if the timer expires.\n\
A negative value disables the timer.",
&setlist);
c = add_show_from_set (c, &showlist);
/* FIXME: must be done after for now. */
tm_print_insn = arc_get_disassembler (bfd_mach_arc_base, 1 /*FIXME*/);
}

View File

@ -1,6 +1,6 @@
/* Parameters for target machine ARC, for GDB, the GNU debugger.
Copyright (C) 1995 Free Software Foundation, Inc.
Contributed by Cygnus Support Corporation.
Contributed by Cygnus Support.
This file is part of GDB.
@ -18,8 +18,11 @@ 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. */
/* Byte order is configurable, but this machine runs little-endian. */
#define TARGET_BYTE_ORDER LITTLE_ENDIAN
/* Used by arc-tdep.c to set the default cpu type. */
#define DEFAULT_ARC_CPU_TYPE "base"
/* Byte order is selectable. */
#define TARGET_BYTE_ORDER_SELECTABLE
/* We have IEEE floating point, if we have any float at all. */
#define IEEE_FLOAT
@ -28,31 +31,61 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
Zero on most machines. */
#define FUNCTION_START_OFFSET 0
/* Advance pc across any function entry prologue instructions
to reach some "real" code. */
/* Advance PC across any function entry prologue instructions
to reach some "real" code. SKIP_PROLOGUE_FRAMELESS_P advances
the PC past some of the prologue, but stops as soon as it
knows that the function has a frame. Its result is equal
to its input PC if the function is frameless, unequal otherwise. */
#define SKIP_PROLOGUE(pc) { pc = skip_prologue (pc); }
extern CORE_ADDR skip_prologue ();
#define SKIP_PROLOGUE(pc) \
{ pc = skip_prologue (pc, 0); }
#define SKIP_PROLOGUE_FRAMELESS_P(pc) \
{ pc = skip_prologue (pc, 1); }
extern CORE_ADDR skip_prologue PARAMS ((CORE_ADDR, int));
/* Sequence of bytes for breakpoint instruction. */
#define BREAKPOINT {0x01, 0x80, 0xbe, 0x1f}
/* Sequence of bytes for breakpoint instruction.
??? The current value is "sr -1,[-1]" and is for the simulator only.
The simulator watches for this and does the right thing.
The hardware version will have to associate with each breakpoint
the sequence "flag 1; nop; nop; nop". IE: The breakpoint insn will not
be a fixed set of bits but instead will be a branch to a semi-random
address. Presumably this will be cleaned up for "second silicon". */
#define BIG_BREAKPOINT { 0x12, 0x1f, 0xff, 0xff }
#define LITTLE_BREAKPOINT { 0xff, 0xff, 0x1f, 0x12 }
#define DECR_PC_AFTER_BREAK 4
/* ??? This value may eventually be correct (if/when proper breakpoints
are added). Until then no value is correct so leave as is and cope. */
#define DECR_PC_AFTER_BREAK 8
/* We don't have a reliable single step facility.
??? We do have a cycle single step facility, but that won't work. */
#define NO_SINGLE_STEP
extern int one_stepped;
extern void single_step PARAMS ((int));
/* Given a pc value as defined by the hardware, return the real address.
Remember that on the ARC blink contains that status register which
includes PC + flags (so we have to mask out the flags). */
#define ARC_PC_TO_REAL_ADDRESS(pc) (((pc) & 0xffffff) << 2)
/* Immediately after a function call, return the saved pc.
Can't always 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 (BLINK_REGNUM))
#define SAVED_PC_AFTER_CALL(frame) \
(ARC_PC_TO_REAL_ADDRESS (read_register (BLINK_REGNUM)))
/* Stack grows upward */
#define INNER_THAN <
/* Nonzero if instruction at pc is a return instruction. */
/* Nonzero if instruction at pc is a return instruction.
This is the "j [blink]" insn (with or without conditionals or delay
slots). */
#define ABOUT_TO_RETURN(pc) (read_memory_integer(pc,4) == 0x380f8000)
#define ABOUT_TO_RETURN(pc) \
((read_memory_integer(pc, 4) & 0xffffff80) == 0x380f8000)
/* Say how long (ordinary) registers are. This is a piece of bogosity
used in push_word and a few other places; REGISTER_RAW_SIZE is the
@ -60,7 +93,7 @@ extern CORE_ADDR skip_prologue ();
#define REGISTER_SIZE 4
/* Number of machine registers */
#define NUM_REGS 91
#define NUM_REGS 92
/* Initializer for an array of names of registers.
There should be NUM_REGS strings in this initializer. */
@ -97,6 +130,11 @@ extern CORE_ADDR skip_prologue ();
#define AUX_BEG_REGNUM 61 /* aux reg begins */
#define AUX_END_REGNUM 90 /* aux reg ends, pc not real aux reg */
/* Fake registers used to mark immediate data. */
#define SHIMM_FLAG_REGNUM 61
#define LIMM_REGNUM 62
#define SHIMM_REGNUM 63
#define AUX_REG_MAP \
{ \
{ 0, 1, 2, 3, 4, 5, \
@ -129,7 +167,7 @@ extern CORE_ADDR skip_prologue ();
/* Total amount of space needed to store our copies of the machine's
register state, the array `registers'. */
#define REGISTER_BYTES (91*4)
#define REGISTER_BYTES (NUM_REGS * 4)
/* Index within `registers' of the first byte of the space for register N. */
#define REGISTER_BYTE(N) (4*(N))
@ -165,7 +203,7 @@ extern CORE_ADDR skip_prologue ();
this is also an argument. This is used in call_function to build a
stack, and in value_being_returned to print return values.
On arc, a structure is always retunred with pointer in r??. */
On arc, a structure is always retunred with pointer in r0. */
#define USE_STRUCT_CONVENTION(gcc_p, type) 1
@ -199,11 +237,6 @@ extern CORE_ADDR skip_prologue ();
/* 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.
However, if FRAME_CHAIN_VALID returns zero,
it means the given frame is the outermost one and has no caller. */
/* We cache information about saved registers in the frame structure,
to save us from having to re-scan function prologues every time
a register in a non-current frame is accessed. */
@ -221,17 +254,20 @@ extern CORE_ADDR skip_prologue ();
#define INIT_EXTRA_FRAME_INFO(fromleaf, fi) \
((fi)->fsr = 0, (fi)->arg_pointer = -1)
/* FRAME_CHAIN takes a frame's nominal address
and produces the frame's chain-pointer.
However, if FRAME_CHAIN_VALID returns zero,
it means the given frame is the outermost one and has no caller. */
/* On the arc, we get the chain pointer by reading the PFP saved
on the stack. */
/* the PFP and RPC is in fp and fp+4. or it is in fp+4 and fp+8 ??? */
/* The PFP and RPC is in fp and fp+4. */
#define FRAME_CHAIN(thisframe) \
(read_memory_integer (FRAME_FP(thisframe), 4))
(read_memory_integer (FRAME_FP (thisframe), 4))
/* FRAME_CHAIN_VALID returns zero if the given frame is the outermost one
and has no caller.
#define FRAME_CHAIN_VALID(thisframe) \
1
and has no caller. */
#define FRAME_CHAIN_VALID(chain, thisframe) ((chain) != 0)
/* 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
@ -242,24 +278,28 @@ extern CORE_ADDR skip_prologue ();
if ((FI)->signal_handler_caller) \
(FRAMELESS) = 0; \
else \
(FRAMELESS) = frameless_look_for_prologue(FI); \
(FRAMELESS) = frameless_look_for_prologue (FI); \
} while (0)
#define FRAME_SAVED_PC(frame) \
(read_memory_integer(FRAME_CHAIN(frame)+8,4))
/* Where is the PC for a specific frame.
A leaf function may never save blink, so we have to check for that here. */
/* On the ARC, FRAME_ARGS_ADDRESS should return the value of
g14 as passed into the frame, if known. We need a function for this.
#define FRAME_SAVED_PC(frame) (arc_frame_saved_pc (frame))
struct frame_info; /* in case frame.h not included yet */
CORE_ADDR arc_frame_saved_pc PARAMS ((struct frame_info *));
/* If the argument is on the stack, it will be here.
We cache this value in the frame info if we've already looked it up. */
/* ??? Is the arg_pointer check necessary? */
#define FRAME_ARGS_ADDRESS(fi) \
(((fi)->arg_pointer != -1)? (fi)->arg_pointer: (fi)->frame + 4)
#define FRAME_ARGS_ADDRESS(fi) \
(((fi)->arg_pointer != -1) ? (fi)->arg_pointer : (fi)->frame)
/* This is the same except it should return 0 when
it does not really know where the args are, rather than guessing.
This value is not cached since it is only used infrequently. */
#define FRAME_LOCALS_ADDRESS(fi) (fi)->frame + 4
#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
/* Set NUMARGS to the number of args passed to a frame.
Can return -1, meaning no way to tell. */

View File

@ -894,20 +894,10 @@ arc_mourn ()
}
#ifdef REMOTE_BREAKPOINT
/* On some machines, e.g. 68k, we may use a different breakpoint instruction
than other targets. */
static unsigned char break_insn[] = REMOTE_BREAKPOINT;
/* Check that it fits in BREAKPOINT_MAX bytes. */
static unsigned char check_break_insn_size[BREAKPOINT_MAX] = REMOTE_BREAKPOINT;
#else /* No REMOTE_BREAKPOINT. */
static unsigned char break_insn[] = BREAKPOINT;
#endif /* No REMOTE_BREAKPOINT. */
static unsigned char big_break_insn[] = BIG_BREAKPOINT;
static unsigned char little_break_insn[] = LITTLE_BREAKPOINT;
#define BREAKPOINT_LEN (sizeof little_break_insn)
/* Insert a breakpoint on targets that don't have any better breakpoint
support. We read the contents of the target location and stash it,
@ -924,9 +914,16 @@ arc_insert_breakpoint (addr, contents_cache)
{
int val;
val = target_read_memory (addr, contents_cache, sizeof break_insn);
val = target_read_memory (addr, contents_cache, BREAKPOINT_LEN);
if (val == 0)
val = target_write_memory (addr, (char *)break_insn, sizeof break_insn);
{
if (TARGET_BYTE_ORDER == BIG_ENDIAN)
val = target_write_memory (addr, (char *) big_break_insn,
BREAKPOINT_LEN);
else
val = target_write_memory (addr, (char *) little_break_insn,
BREAKPOINT_LEN);
}
return val;
}
@ -935,7 +932,7 @@ arc_remove_breakpoint (addr, contents_cache)
CORE_ADDR addr;
char *contents_cache;
{
return target_write_memory (addr, contents_cache, sizeof break_insn);
return target_write_memory (addr, contents_cache, BREAKPOINT_LEN);
}
/* switch_command
@ -961,13 +958,16 @@ switch_command (args, fromtty)
switch (proc)
{
case 0:
tm_print_insn = arc_get_disassembler (bfd_mach_arc_audio);
tm_print_insn = arc_get_disassembler (bfd_mach_arc_audio,
TARGET_BYTE_ORDER == BIG_ENDIAN);
break;
case 1:
tm_print_insn = arc_get_disassembler (bfd_mach_arc_graphics);
tm_print_insn = arc_get_disassembler (bfd_mach_arc_graphics,
TARGET_BYTE_ORDER == BIG_ENDIAN);
break;
case 2:
tm_print_insn = arc_get_disassembler (bfd_mach_arc_host);
tm_print_insn = arc_get_disassembler (bfd_mach_arc_host,
TARGET_BYTE_ORDER == BIG_ENDIAN);
break;
}
@ -1026,7 +1026,4 @@ void
_initialize_remote_arc ()
{
add_target (&arc_ops);
add_com ("switch <processor>", class_obscure, switch_command,
"Switch to debug a different processor, can be one of 'host', \
'graphic' and 'audio'.");
}