315 lines
8.3 KiB
C
315 lines
8.3 KiB
C
|
/* Target-dependent code for the SPARC 64 for GDB, the GNU debugger.
|
|||
|
Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
|
|||
|
Contributed by Doug Evans (dje@cygnus.com).
|
|||
|
|
|||
|
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 "obstack.h"
|
|||
|
#include "target.h"
|
|||
|
#include "ieee-float.h"
|
|||
|
|
|||
|
/*#include "symfile.h" /* for objfiles.h */
|
|||
|
/*#include "objfiles.h" /* for find_pc_section */
|
|||
|
|
|||
|
/* This file contains replacements and additions to sparc-tdep.c only.
|
|||
|
Some of this code has been written for a day when we can merge at least
|
|||
|
some of this with sparc-tdep.c. Macro TARGET_SPARC64 exists to allow some
|
|||
|
code to potentially be used by both. */
|
|||
|
|
|||
|
#define TARGET_SPARC64 1 /* later make a config parm or some such */
|
|||
|
|
|||
|
/* From infrun.c */
|
|||
|
extern int stop_after_trap;
|
|||
|
|
|||
|
/* Branches with prediction are treated like their non-predicting cousins. */
|
|||
|
/* FIXME: What about floating point branches? */
|
|||
|
|
|||
|
typedef enum
|
|||
|
{
|
|||
|
Error, not_branch, bicc, bicca, ba, baa, ticc, ta, done_retry
|
|||
|
} branch_type;
|
|||
|
|
|||
|
/* Simulate single-step ptrace call for sun4. Code written by Gary
|
|||
|
Beihl (beihl@mcc.com). */
|
|||
|
|
|||
|
/* npc4 and next_pc describe the situation at the time that the
|
|||
|
step-breakpoint was set, not necessary the current value of NPC_REGNUM. */
|
|||
|
static CORE_ADDR next_pc, npc4, target;
|
|||
|
static int brknpc4, brktrg;
|
|||
|
typedef char binsn_quantum[BREAKPOINT_MAX];
|
|||
|
static binsn_quantum break_mem[3];
|
|||
|
|
|||
|
/* Non-zero if we just simulated a single-step ptrace call. This is
|
|||
|
needed because we cannot remove the breakpoints in the inferior
|
|||
|
process until after the `wait' in `wait_for_inferior'. Used for
|
|||
|
sun4. */
|
|||
|
|
|||
|
int one_stepped;
|
|||
|
|
|||
|
/* sparc64_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 (as on all SPARCs). 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. */
|
|||
|
|
|||
|
/* FIXME: When the code is releasable, sparc's single step could become this
|
|||
|
one, removing the duplication. */
|
|||
|
|
|||
|
void
|
|||
|
sparc64_single_step (ignore)
|
|||
|
int ignore; /* pid, but we don't need it */
|
|||
|
{
|
|||
|
branch_type br, isbranch();
|
|||
|
CORE_ADDR pc;
|
|||
|
long pc_instruction;
|
|||
|
|
|||
|
if (!one_stepped)
|
|||
|
{
|
|||
|
/* Always set breakpoint for NPC. */
|
|||
|
next_pc = read_register (NPC_REGNUM);
|
|||
|
npc4 = next_pc + 4; /* branch not taken */
|
|||
|
|
|||
|
target_insert_breakpoint (next_pc, break_mem[0]);
|
|||
|
/* printf ("set break at %x\n",next_pc); */
|
|||
|
|
|||
|
pc = read_register (PC_REGNUM);
|
|||
|
pc_instruction = read_memory_integer (pc, sizeof(pc_instruction));
|
|||
|
br = isbranch (pc_instruction, pc, &target);
|
|||
|
brknpc4 = brktrg = 0;
|
|||
|
|
|||
|
if (br == bicca)
|
|||
|
{
|
|||
|
/* Conditional annulled branch will either end up at
|
|||
|
npc (if taken) or at npc+4 (if not taken).
|
|||
|
Trap npc+4. */
|
|||
|
brknpc4 = 1;
|
|||
|
target_insert_breakpoint (npc4, break_mem[1]);
|
|||
|
}
|
|||
|
else if ((br == baa && target != next_pc)
|
|||
|
|| (TARGET_SPARC64 && br == done_retry))
|
|||
|
{
|
|||
|
/* Unconditional annulled branch will always end up at
|
|||
|
the target. */
|
|||
|
brktrg = 1;
|
|||
|
target_insert_breakpoint (target, break_mem[2]);
|
|||
|
}
|
|||
|
|
|||
|
/* We are ready to let it go */
|
|||
|
one_stepped = 1;
|
|||
|
return;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* Remove breakpoints */
|
|||
|
target_remove_breakpoint (next_pc, break_mem[0]);
|
|||
|
|
|||
|
if (brknpc4)
|
|||
|
target_remove_breakpoint (npc4, break_mem[1]);
|
|||
|
|
|||
|
if (brktrg)
|
|||
|
target_remove_breakpoint (target, break_mem[2]);
|
|||
|
|
|||
|
one_stepped = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* FIXME: sparc64_frame_chain() is temporary. sparc_frame_chain() can
|
|||
|
be fixed to support both of us. */
|
|||
|
|
|||
|
#define FRAME_SAVED_L0 0 /* Byte offset from SP */
|
|||
|
#define FRAME_SAVED_I0 (8*REGISTER_RAW_SIZE (0)) /* Byte offset from SP */
|
|||
|
|
|||
|
CORE_ADDR
|
|||
|
sparc64_frame_chain (thisframe)
|
|||
|
FRAME thisframe;
|
|||
|
{
|
|||
|
REGISTER_TYPE retval;
|
|||
|
int err;
|
|||
|
CORE_ADDR addr;
|
|||
|
|
|||
|
addr = thisframe->frame + FRAME_SAVED_I0 +
|
|||
|
REGISTER_RAW_SIZE (0) * (FP_REGNUM - I0_REGNUM);
|
|||
|
err = target_read_memory (addr, (char *) &retval, sizeof (REGISTER_TYPE));
|
|||
|
if (err)
|
|||
|
return 0;
|
|||
|
SWAP_TARGET_AND_HOST (&retval, sizeof (retval));
|
|||
|
return retval;
|
|||
|
}
|
|||
|
|
|||
|
CORE_ADDR
|
|||
|
sparc64_extract_struct_value_address (regbuf)
|
|||
|
char regbuf[REGISTER_BYTES];
|
|||
|
{
|
|||
|
CORE_ADDR addr;
|
|||
|
|
|||
|
/* FIXME: We assume a non-leaf function. */
|
|||
|
addr = read_register (I0_REGNUM);
|
|||
|
return addr;
|
|||
|
}
|
|||
|
|
|||
|
/* Find the pc saved in frame FRAME. */
|
|||
|
/* FIXME: This function can be removed when sparc_frame_saved_pc
|
|||
|
handles us too. */
|
|||
|
|
|||
|
CORE_ADDR
|
|||
|
sparc64_frame_saved_pc (frame)
|
|||
|
FRAME frame;
|
|||
|
{
|
|||
|
int err;
|
|||
|
REGISTER_TYPE retval;
|
|||
|
CORE_ADDR addr,prev_pc;
|
|||
|
|
|||
|
if (get_current_frame () == frame) /* FIXME, debug check. Remove >=gdb-4.6 */
|
|||
|
{
|
|||
|
if (read_register (SP_REGNUM) != frame->bottom) abort();
|
|||
|
}
|
|||
|
|
|||
|
addr = frame->bottom + FRAME_SAVED_I0 +
|
|||
|
REGISTER_RAW_SIZE (0) * (I7_REGNUM - I0_REGNUM);
|
|||
|
err = target_read_memory (addr, (char *) &retval, sizeof (REGISTER_TYPE));
|
|||
|
if (err)
|
|||
|
return 0;
|
|||
|
SWAP_TARGET_AND_HOST (&retval, sizeof (retval));
|
|||
|
|
|||
|
/* CORE_ADDR isn't always the same size as REGISTER_TYPE, so convert. */
|
|||
|
|
|||
|
prev_pc = (CORE_ADDR) retval;
|
|||
|
return PC_ADJUST (prev_pc);
|
|||
|
}
|
|||
|
|
|||
|
/* Check instruction at ADDR to see if it is an annulled branch or other
|
|||
|
instruction whose npc isn't pc+4 (eg: trap, done, retry).
|
|||
|
All other instructions will go to NPC or will trap.
|
|||
|
Set *TARGET if we find a candidate branch; set to zero if not. */
|
|||
|
|
|||
|
branch_type
|
|||
|
isbranch (instruction, addr, target)
|
|||
|
long instruction;
|
|||
|
CORE_ADDR addr, *target;
|
|||
|
{
|
|||
|
branch_type val = not_branch;
|
|||
|
long int offset; /* Must be signed for sign-extend. */
|
|||
|
union
|
|||
|
{
|
|||
|
unsigned long int code;
|
|||
|
struct
|
|||
|
{
|
|||
|
unsigned int op:2;
|
|||
|
unsigned int a:1;
|
|||
|
unsigned int cond:4;
|
|||
|
unsigned int op2:3;
|
|||
|
unsigned int disp22:22;
|
|||
|
} b;
|
|||
|
struct
|
|||
|
{
|
|||
|
unsigned int op:2;
|
|||
|
unsigned int a:1;
|
|||
|
unsigned int cond:4;
|
|||
|
unsigned int op2:3;
|
|||
|
unsigned int cc:2;
|
|||
|
unsigned int p:1;
|
|||
|
unsigned int disp19:19;
|
|||
|
} bp;
|
|||
|
struct
|
|||
|
{
|
|||
|
unsigned int op:2;
|
|||
|
unsigned int a:1;
|
|||
|
unsigned int zero:1;
|
|||
|
unsigned int rcond:3;
|
|||
|
unsigned int op2:3;
|
|||
|
unsigned int disp16hi:2;
|
|||
|
unsigned int p:1;
|
|||
|
unsigned int rs1:5;
|
|||
|
unsigned int disp16lo:14;
|
|||
|
} bpr;
|
|||
|
struct
|
|||
|
{
|
|||
|
unsigned int op:2;
|
|||
|
unsigned int fcn:5;
|
|||
|
unsigned int op3:6;
|
|||
|
unsigned int reserved:19;
|
|||
|
} dr;
|
|||
|
} insn;
|
|||
|
|
|||
|
*target = 0;
|
|||
|
insn.code = instruction;
|
|||
|
|
|||
|
if (insn.b.op == 0
|
|||
|
&& (insn.b.op2 == 1 || insn.b.op2 == 2 || insn.b.op2 ==3
|
|||
|
|| insn.b.op2 == 5 || insn.b.op2 == 6))
|
|||
|
{
|
|||
|
if (insn.b.cond == 8)
|
|||
|
val = insn.b.a ? baa : ba;
|
|||
|
else
|
|||
|
val = insn.b.a ? bicca : bicc;
|
|||
|
switch (insn.b.op2)
|
|||
|
{
|
|||
|
case 1: /* bpcc */
|
|||
|
offset = 4 * ((int) (insn.bp.disp19 << 13) >> 13);
|
|||
|
break;
|
|||
|
case 2: /* bicc */
|
|||
|
offset = 4 * ((int) (insn.b.disp22 << 10) >> 10);
|
|||
|
break;
|
|||
|
case 3: /* bpr */
|
|||
|
offset = 4 * ((int) ((insn.bpr.disp16hi << 10)
|
|||
|
|| (insn.bpr.disp16lo << 18)) >> 13);
|
|||
|
break;
|
|||
|
case 5: /* fbpfcc */
|
|||
|
offset = 4 * ((int) (insn.bp.disp19 << 13) >> 13);
|
|||
|
break;
|
|||
|
case 6: /* fbfcc */
|
|||
|
offset = 4 * ((int) (insn.b.disp22 << 10) >> 10);
|
|||
|
break;
|
|||
|
}
|
|||
|
*target = addr + offset;
|
|||
|
}
|
|||
|
else if (insn.dr.op == 2 && insn.dr.op3 == 62)
|
|||
|
{
|
|||
|
if (insn.dr.fcn == 0)
|
|||
|
{
|
|||
|
/* done */
|
|||
|
*target = read_register (TNPC_REGNUM);
|
|||
|
val = done_retry;
|
|||
|
}
|
|||
|
else if (insn.dr.fcn == 1)
|
|||
|
{
|
|||
|
/* retry */
|
|||
|
*target = read_register (TPC_REGNUM);
|
|||
|
val = done_retry;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return val;
|
|||
|
}
|
|||
|
|
|||
|
/* We try to support 32 bit and 64 bit pointers.
|
|||
|
We are called when the Shade target is selected by shadeif.c. */
|
|||
|
|
|||
|
int target_ptr_bit = 64; /* default */
|
|||
|
|
|||
|
void
|
|||
|
set_target_ptr_bit(ptr_bit)
|
|||
|
int ptr_bit;
|
|||
|
{
|
|||
|
target_ptr_bit = ptr_bit;
|
|||
|
}
|