* MIPS CPU-specific dissasembly extensions. Now TM_PRINT_INSN_MACH from tm.h
sets a default mach for disassembly, just like sparc port. c.f. PR 15371. Tue Apr 21 11:20:54 1998 Frank Ch. Eigler <fche@cygnus.com> * mips-tdep.c (gdb_print_insn_mips): Disassemble MIPS instructions with subtarget-specific `mach', rather than fixed default. * config/mips/tm-mips.h (TM_PRINT_INSN_MACH): New macro, default disassembly `mach'. start-sanitize-r5900 * config/mips/tm-r5900.h (TM_PRINT_INSN_MACH): Override. end-sanitize-r5900 start-sanitize-sky * config/mips/tm-txvu.h (TM_PRINT_INSN_MACH): Override. end-sanitize-sky
This commit is contained in:
parent
171c7bbffe
commit
88ff9e0600
@ -1,3 +1,22 @@
|
||||
Tue Apr 21 11:20:54 1998 Frank Ch. Eigler <fche@cygnus.com>
|
||||
|
||||
* mips-tdep.c (gdb_print_insn_mips): Disassemble MIPS instructions
|
||||
with subtarget-specific `mach', rather than fixed default.
|
||||
* config/mips/tm-mips.h (TM_PRINT_INSN_MACH): New macro, default
|
||||
disassembly `mach'.
|
||||
start-sanitize-r5900
|
||||
* config/mips/tm-r5900.h (TM_PRINT_INSN_MACH): Override.
|
||||
end-sanitize-r5900
|
||||
start-sanitize-sky
|
||||
* config/mips/tm-txvu.h (TM_PRINT_INSN_MACH): Override.
|
||||
end-sanitize-sky
|
||||
|
||||
Mon Apr 20 15:35:03 1998 Philippe De Muyter <phdm@macqel.be>
|
||||
|
||||
* coffread.c (decode_base_type): Treat a long field with size greater
|
||||
than TARGET_LONG_BIT as long long.
|
||||
* values.c (value_from_longest): Print code value in error message.
|
||||
|
||||
Mon Apr 20 15:32:21 1998 Mark Kettenis <kettenis@phys.uva.nl>
|
||||
|
||||
* gdb/gdb_string.h (strdup): Declare only if not defined as a
|
||||
|
@ -529,6 +529,11 @@ extern struct frame_info *setup_arbitrary_frame PARAMS ((int, CORE_ADDR *));
|
||||
|
||||
#define COERCE_FLOAT_TO_DOUBLE (current_language -> la_language == language_c)
|
||||
|
||||
/* Select the default mips disassembler */
|
||||
|
||||
#define TM_PRINT_INSN_MACH 0
|
||||
|
||||
|
||||
/* These are defined in mdebugread.c and are used in mips-tdep.c */
|
||||
extern CORE_ADDR sigtramp_address, sigtramp_end;
|
||||
extern void fixup_sigtramp PARAMS ((void));
|
||||
|
443
gdb/mips-tdep.c
443
gdb/mips-tdep.c
@ -353,6 +353,445 @@ mips_fetch_instruction (addr)
|
||||
}
|
||||
|
||||
|
||||
/* These the fields of 32 bit mips instructions */
|
||||
#define mips32_op(x) (x >> 25)
|
||||
#define itype_op(x) (x >> 25)
|
||||
#define itype_rs(x) ((x >> 21)& 0x1f)
|
||||
#define itype_rt(x) ((x >> 16) & 0x1f)
|
||||
#define itype_immediate(x) ( x & 0xffff)
|
||||
|
||||
#define jtype_op(x) (x >> 25)
|
||||
#define jtype_target(x) ( x & 0x03fffff)
|
||||
|
||||
#define rtype_op(x) (x >>25)
|
||||
#define rtype_rs(x) ((x>>21) & 0x1f)
|
||||
#define rtype_rt(x) ((x>>16) & 0x1f)
|
||||
#define rtype_rd(x) ((x>>11) & 0x1f)
|
||||
#define rtype_shamt(x) ((x>>6) & 0x1f)
|
||||
#define rtype_funct(x) (x & 0x3f )
|
||||
|
||||
static CORE_ADDR
|
||||
mips32_relative_offset(unsigned long inst)
|
||||
{ long x ;
|
||||
x = itype_immediate(inst) ;
|
||||
if (x & 0x8000) /* sign bit set */
|
||||
{
|
||||
x |= 0xffff0000 ; /* sign extension */
|
||||
}
|
||||
x = x << 2 ;
|
||||
return x ;
|
||||
}
|
||||
|
||||
/* Determine whate to set a single step breakpoint while considering
|
||||
branch prediction */
|
||||
CORE_ADDR
|
||||
mips32_next_pc(CORE_ADDR pc)
|
||||
{
|
||||
unsigned long inst ;
|
||||
int op ;
|
||||
inst = mips_fetch_instruction(pc) ;
|
||||
if ((inst & 0xe0000000) != 0) /* Not a special, junp or branch instruction */
|
||||
{ if ((inst >> 27) == 5) /* BEQL BNEZ BLEZL BGTZE , bits 0101xx */
|
||||
{ op = ((inst >> 25) & 0x03) ;
|
||||
switch (op)
|
||||
{
|
||||
case 0 : goto equal_branch ; /* BEQL */
|
||||
case 1 : goto neq_branch ; /* BNEZ */
|
||||
case 2 : goto less_branch ; /* BLEZ */
|
||||
case 3 : goto greater_branch ; /* BGTZ */
|
||||
default : pc += 4 ;
|
||||
}
|
||||
}
|
||||
else pc += 4 ; /* Not a branch, next instruction is easy */
|
||||
}
|
||||
else
|
||||
{ /* This gets way messy */
|
||||
|
||||
/* Further subdivide into SPECIAL, REGIMM and other */
|
||||
switch (op = ((inst >> 26) & 0x07)) /* extract bits 28,27,26 */
|
||||
{
|
||||
case 0 : /* SPECIAL */
|
||||
op = rtype_funct(inst) ;
|
||||
switch (op)
|
||||
{
|
||||
case 8 : /* JR */
|
||||
case 9 : /* JALR */
|
||||
pc = read_register(rtype_rs(inst)) ; /* Set PC to that address */
|
||||
break ;
|
||||
default: pc += 4 ;
|
||||
}
|
||||
|
||||
break ; /* end special */
|
||||
case 1 : /* REGIMM */
|
||||
{
|
||||
op = jtype_op(inst) ; /* branch condition */
|
||||
switch (jtype_op(inst))
|
||||
{
|
||||
case 0 : /* BLTZ */
|
||||
case 2 : /* BLTXL */
|
||||
case 16 : /* BLTZALL */
|
||||
case 18 : /* BLTZALL */
|
||||
less_branch:
|
||||
if (read_register(itype_rs(inst)) < 0)
|
||||
pc += mips32_relative_offset(inst) + 4 ;
|
||||
else pc += 8 ; /* after the delay slot */
|
||||
break ;
|
||||
case 1 : /* GEZ */
|
||||
case 3 : /* BGEZL */
|
||||
case 17 : /* BGEZAL */
|
||||
case 19 : /* BGEZALL */
|
||||
greater_equal_branch:
|
||||
if (read_register(itype_rs(inst)) >= 0)
|
||||
pc += mips32_relative_offset(inst) + 4 ;
|
||||
else pc += 8 ; /* after the delay slot */
|
||||
break ;
|
||||
/* All of the other intructions in the REGIMM catagory */
|
||||
default: pc += 4 ;
|
||||
}
|
||||
}
|
||||
break ; /* end REGIMM */
|
||||
case 2 : /* J */
|
||||
case 3 : /* JAL */
|
||||
{ unsigned long reg ;
|
||||
reg = jtype_target(inst) << 2 ;
|
||||
pc = reg + ((pc+4) & 0xf0000000) ;
|
||||
/* Whats this mysterious 0xf000000 adjustment ??? */
|
||||
}
|
||||
break ;
|
||||
/* FIXME case JALX :*/
|
||||
{ unsigned long reg ;
|
||||
reg = jtype_target(inst) << 2 ;
|
||||
pc = reg + ((pc+4) & 0xf0000000) + 1 ; /* yes, +1 */
|
||||
/* Add 1 to indicate 16 bit mode - Invert ISA mode */
|
||||
}
|
||||
break ; /* The new PC will be alternate mode */
|
||||
case 4 : /* BEQ , BEQL */
|
||||
equal_branch :
|
||||
if (read_register(itype_rs(inst)) ==
|
||||
read_register(itype_rt(inst)))
|
||||
pc += mips32_relative_offset(inst) + 4 ;
|
||||
else pc += 8 ;
|
||||
break ;
|
||||
case 5 : /* BNE , BNEL */
|
||||
neq_branch :
|
||||
if (read_register(itype_rs(inst)) !=
|
||||
read_register(itype_rs(inst)))
|
||||
pc += mips32_relative_offset(inst) + 4 ;
|
||||
else pc += 8 ;
|
||||
break ;
|
||||
case 6 : /* BLEZ , BLEZL */
|
||||
less_zero_branch:
|
||||
if (read_register(itype_rs(inst) <= 0))
|
||||
pc += mips32_relative_offset(inst) + 4 ;
|
||||
else pc += 8 ;
|
||||
break ;
|
||||
case 7 :
|
||||
greater_branch : /* BGTZ BGTZL */
|
||||
if (read_register(itype_rs(inst) > 0))
|
||||
pc += mips32_relative_offset(inst) + 4 ;
|
||||
else pc += 8 ;
|
||||
break ;
|
||||
default : pc += 8 ;
|
||||
} /* switch */
|
||||
} /* else */
|
||||
return pc ;
|
||||
} /* mips32_next_pc */
|
||||
|
||||
/* Decoding the next place to set a breakpoint is irregular for the
|
||||
mips 16 variant, but fortunatly, there fewer instructions. We have to cope
|
||||
ith extensions for 16 bit instructions and a pair of actual 32 bit instructions.
|
||||
We dont want to set a single step instruction on the extend instruction
|
||||
either.
|
||||
*/
|
||||
|
||||
/* Lots of mips16 instruction formats */
|
||||
/* Predicting jumps requires itype,ritype,i8type
|
||||
and their extensions extItype,extritype,extI8type
|
||||
*/
|
||||
enum mips16_inst_fmts
|
||||
{
|
||||
itype, /* 0 immediate 5,10 */
|
||||
ritype, /* 1 5,3,8 */
|
||||
rrtype, /* 2 5,3,3,5 */
|
||||
rritype, /* 3 5,3,3,5 */
|
||||
rrrtype, /* 4 5,3,3,3,2 */
|
||||
rriatype, /* 5 5,3,3,1,4 */
|
||||
shifttype, /* 6 5,3,3,3,2 */
|
||||
i8type, /* 7 5,3,8 */
|
||||
i8movtype, /* 8 5,3,3,5 */
|
||||
i8mov32rtype, /* 9 5,3,5,3 */
|
||||
i64type, /* 10 5,3,8 */
|
||||
ri64type, /* 11 5,3,3,5 */
|
||||
jalxtype, /* 12 5,1,5,5,16 - a 32 bit instruction */
|
||||
exiItype, /* 13 5,6,5,5,1,1,1,1,1,1,5 */
|
||||
extRitype, /* 14 5,6,5,5,3,1,1,1,5 */
|
||||
extRRItype, /* 15 5,5,5,5,3,3,5 */
|
||||
extRRIAtype, /* 16 5,7,4,5,3,3,1,4 */
|
||||
EXTshifttype, /* 17 5,5,1,1,1,1,1,1,5,3,3,1,1,1,2 */
|
||||
extI8type, /* 18 5,6,5,5,3,1,1,1,5 */
|
||||
extI64type, /* 19 5,6,5,5,3,1,1,1,5 */
|
||||
extRi64type, /* 20 5,6,5,5,3,3,5 */
|
||||
extshift64type /* 21 5,5,1,1,1,1,1,1,5,1,1,1,3,5 */
|
||||
} ;
|
||||
/* I am heaping all the fields of the formats into one structure and then,
|
||||
only the fields which are involved in instruction extension */
|
||||
struct upk_mips16
|
||||
{
|
||||
unsigned short inst ;
|
||||
enum mips16_inst_fmts fmt ;
|
||||
unsigned long offset ;
|
||||
unsigned int regx ; /* Function in i8 type */
|
||||
unsigned int regy ;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
static void print_unpack(char * comment,
|
||||
struct upk_mips16 * u)
|
||||
{
|
||||
printf("%s %04x ,f(%d) off(%08x) (x(%x) y(%x)\n",
|
||||
comment,u->inst,u->fmt,u->offset,u->regx,u->regy) ;
|
||||
}
|
||||
|
||||
/* The EXT-I, EXT-ri nad EXT-I8 instructions all have the same
|
||||
format for the bits which make up the immediatate extension.
|
||||
*/
|
||||
static unsigned long
|
||||
extended_offset(unsigned long extension)
|
||||
{
|
||||
unsigned long value ;
|
||||
value = (extension >> 21) & 0x3f ; /* * extract 15:11 */
|
||||
value = value << 6 ;
|
||||
value |= (extension >> 16) & 0x1f ; /* extrace 10:5 */
|
||||
value = value << 5 ;
|
||||
value |= extension & 0x01f ; /* extract 4:0 */
|
||||
return value ;
|
||||
}
|
||||
|
||||
/* Only call this function if you know that this is an extendable
|
||||
instruction, It wont malfunction, but why make excess remote memory references?
|
||||
If the immediate operands get sign extended or somthing, do it after
|
||||
the extension is performed.
|
||||
*/
|
||||
/* FIXME: Every one of these cases needs to worry about sign extension
|
||||
when the offset is to be used in relative addressing */
|
||||
|
||||
|
||||
static unsigned short fetch_mips_16(CORE_ADDR pc)
|
||||
{
|
||||
char buf[8] ;
|
||||
pc &= 0xfffffffe ; /* clear the low order bit */
|
||||
target_read_memory(pc,buf,2) ;
|
||||
return extract_unsigned_integer(buf,2) ;
|
||||
}
|
||||
|
||||
static void
|
||||
unpack_mips16(CORE_ADDR pc,
|
||||
struct upk_mips16 * upk)
|
||||
{
|
||||
CORE_ADDR extpc ;
|
||||
unsigned long extension ;
|
||||
int extended ;
|
||||
extpc = (pc - 4) & ~0x01 ; /* Extensions are 32 bit instructions */
|
||||
/* Decrement to previous address and loose the 16bit mode flag */
|
||||
/* return if the instruction was extendable, but not actually extended */
|
||||
extended = ((mips32_op(extension) == 30) ? 1 : 0) ;
|
||||
if (extended) { extension = mips_fetch_instruction(extpc) ;}
|
||||
switch (upk->fmt)
|
||||
{
|
||||
case itype :
|
||||
{
|
||||
unsigned long value ;
|
||||
if (extended)
|
||||
{ value = extended_offset(extension) ;
|
||||
value = value << 11 ; /* rom for the original value */
|
||||
value |= upk->inst & 0x7ff ; /* eleven bits from instruction */
|
||||
}
|
||||
else
|
||||
{ value = upk->inst & 0x7ff ;
|
||||
/* FIXME : Consider sign extension */
|
||||
}
|
||||
upk->offset = value ;
|
||||
}
|
||||
break ;
|
||||
case ritype :
|
||||
case i8type :
|
||||
{ /* A register identifier and an offset */
|
||||
/* Most of the fields are the same as I type but the
|
||||
immediate value is of a different length */
|
||||
unsigned long value ;
|
||||
if (extended)
|
||||
{
|
||||
value = extended_offset(extension) ;
|
||||
value = value << 8 ; /* from the original instruction */
|
||||
value |= upk->inst & 0xff ; /* eleven bits from instruction */
|
||||
upk->regx = (extension >> 8) & 0x07 ; /* or i8 funct */
|
||||
if (value & 0x4000) /* test the sign bit , bit 26 */
|
||||
{ value &= ~ 0x3fff ; /* remove the sign bit */
|
||||
value = -value ;
|
||||
}
|
||||
}
|
||||
else {
|
||||
value = upk->inst & 0xff ; /* 8 bits */
|
||||
upk->regx = (upk->inst >> 8) & 0x07 ; /* or i8 funct */
|
||||
/* FIXME: Do sign extension , this format needs it */
|
||||
if (value & 0x80) /* THIS CONFUSES ME */
|
||||
{ value &= 0xef ; /* remove the sign bit */
|
||||
value = -value ;
|
||||
}
|
||||
|
||||
}
|
||||
upk->offset = value ;
|
||||
break ;
|
||||
}
|
||||
case jalxtype :
|
||||
{
|
||||
unsigned long value ;
|
||||
unsigned short nexthalf ;
|
||||
value = ((upk->inst & 0x1f) << 5) | ((upk->inst >> 5) & 0x1f) ;
|
||||
value = value << 16 ;
|
||||
nexthalf = mips_fetch_instruction(pc+2) ; /* low bit still set */
|
||||
value |= nexthalf ;
|
||||
upk->offset = value ;
|
||||
break ;
|
||||
}
|
||||
default:
|
||||
printf_filtered("Decoding unimplemented instruction format type\n") ;
|
||||
break ;
|
||||
}
|
||||
/* print_unpack("UPK",upk) ; */
|
||||
}
|
||||
|
||||
|
||||
#define mips16_op(x) (x >> 11)
|
||||
|
||||
/* This is a map of the opcodes which ae known to perform branches */
|
||||
static unsigned char map16[32] =
|
||||
{ 0,0,1,1,1,1,0,0,
|
||||
0,0,0,0,1,0,0,0,
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,1,1,0
|
||||
} ;
|
||||
|
||||
static CORE_ADDR add_offset_16(CORE_ADDR pc, int offset)
|
||||
{
|
||||
return ((offset << 2) | ((pc + 2) & (0xf0000000))) ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct upk_mips16 upk ;
|
||||
|
||||
CORE_ADDR mips16_next_pc(CORE_ADDR pc)
|
||||
{
|
||||
int op ;
|
||||
t_inst inst ;
|
||||
/* inst = mips_fetch_instruction(pc) ; - This doesnt always work */
|
||||
inst = fetch_mips_16(pc) ;
|
||||
upk.inst = inst ;
|
||||
op = mips16_op(upk.inst) ;
|
||||
if (map16[op])
|
||||
{
|
||||
int reg ;
|
||||
switch (op)
|
||||
{
|
||||
case 2 : /* Branch */
|
||||
upk.fmt = itype ;
|
||||
unpack_mips16(pc,&upk) ;
|
||||
{ long offset ;
|
||||
offset = upk.offset ;
|
||||
if (offset & 0x800)
|
||||
{ offset &= 0xeff ;
|
||||
offset = - offset ;
|
||||
}
|
||||
pc += (offset << 1) + 2 ;
|
||||
}
|
||||
break ;
|
||||
case 3 : /* JAL , JALX - Watch out, these are 32 bit instruction*/
|
||||
upk.fmt = jalxtype ;
|
||||
unpack_mips16(pc,&upk) ;
|
||||
pc = add_offset_16(pc,upk.offset) ;
|
||||
if ((upk.inst >> 10) & 0x01) /* Exchange mode */
|
||||
pc = pc & ~ 0x01 ; /* Clear low bit, indicate 32 bit mode */
|
||||
else pc |= 0x01 ;
|
||||
break ;
|
||||
case 4 : /* beqz */
|
||||
upk.fmt = ritype ;
|
||||
unpack_mips16(pc,&upk) ;
|
||||
reg = read_register(upk.regx) ;
|
||||
if (reg == 0)
|
||||
pc += (upk.offset << 1) + 2 ;
|
||||
else pc += 2 ;
|
||||
break ;
|
||||
case 5 : /* bnez */
|
||||
upk.fmt = ritype ;
|
||||
unpack_mips16(pc,&upk) ;
|
||||
reg = read_register(upk.regx) ;
|
||||
if (reg != 0)
|
||||
pc += (upk.offset << 1) + 2 ;
|
||||
else pc += 2 ;
|
||||
break ;
|
||||
case 12 : /* I8 Formats btez btnez */
|
||||
upk.fmt = i8type ;
|
||||
unpack_mips16(pc,&upk) ;
|
||||
/* upk.regx contains the opcode */
|
||||
reg = read_register(24) ; /* Test register is 24 */
|
||||
if (((upk.regx == 0) && (reg == 0)) /* BTEZ */
|
||||
|| ((upk.regx == 1 ) && (reg != 0))) /* BTNEZ */
|
||||
/* pc = add_offset_16(pc,upk.offset) ; */
|
||||
pc += (upk.offset << 1) + 2 ;
|
||||
else pc += 2 ;
|
||||
break ;
|
||||
case 29 : /* RR Formats JR, JALR, JALR-RA */
|
||||
upk.fmt = rrtype ;
|
||||
op = upk.inst & 0x1f ;
|
||||
if (op == 0)
|
||||
{
|
||||
upk.regx = (upk.inst >> 8) & 0x07 ;
|
||||
upk.regy = (upk.inst >> 5) & 0x07 ;
|
||||
switch (upk.regy)
|
||||
{
|
||||
case 0 : reg = upk.regx ; break ;
|
||||
case 1 : reg = 31 ; break ; /* Function return instruction*/
|
||||
case 2 : reg = upk.regx ; break ;
|
||||
default: reg = 31 ; break ; /* BOGUS Guess */
|
||||
}
|
||||
pc = read_register(reg) ;
|
||||
}
|
||||
else pc += 2 ;
|
||||
break ;
|
||||
case 30 : /* This is an extend instruction */
|
||||
pc += 4 ; /* Dont be setting breakpints on the second half */
|
||||
break ;
|
||||
default :
|
||||
printf("Filtered - next PC probably incorrrect due to jump inst\n");
|
||||
pc += 2 ;
|
||||
break ;
|
||||
}
|
||||
}
|
||||
else pc+= 2 ; /* just a good old instruction */
|
||||
/* See if we CAN actually break on the next instruction */
|
||||
/* printf("NXTm16PC %08x\n",(unsigned long)pc) ; */
|
||||
return pc ;
|
||||
} /* mips16_next_pc */
|
||||
|
||||
/* The mips_next_pc function supports single_tep when the remote target monitor or
|
||||
stub is not developed enough to so a single_step.
|
||||
It works by decoding the current instruction and predicting where a branch
|
||||
will go. This isnt hard because all the data is available.
|
||||
The MIPS32 and MIPS16 variants are quite different
|
||||
*/
|
||||
CORE_ADDR mips_next_pc(CORE_ADDR pc)
|
||||
{
|
||||
t_inst inst ;
|
||||
/* inst = mips_fetch_instruction(pc) ; */
|
||||
/* if (pc_is_mips16) <----- This is failing */
|
||||
if (pc & 0x01)
|
||||
return mips16_next_pc(pc) ;
|
||||
else return mips32_next_pc(pc) ;
|
||||
} /* mips_next_pc */
|
||||
|
||||
/* Guaranteed to set fci->saved_regs to some values (it never leaves it
|
||||
NULL). */
|
||||
|
||||
@ -2385,9 +2824,9 @@ gdb_print_insn_mips (memaddr, info)
|
||||
it's definitely a 16-bit function. Otherwise, we have to just
|
||||
guess that if the address passed in is odd, it's 16-bits. */
|
||||
if (proc_desc)
|
||||
info->mach = pc_is_mips16 (PROC_LOW_ADDR (proc_desc)) ? 16 : 0;
|
||||
info->mach = pc_is_mips16 (PROC_LOW_ADDR (proc_desc)) ? 16 : TM_PRINT_INSN_MACH;
|
||||
else
|
||||
info->mach = pc_is_mips16 (memaddr) ? 16 : 0;
|
||||
info->mach = pc_is_mips16 (memaddr) ? 16 : TM_PRINT_INSN_MACH;
|
||||
|
||||
/* Round down the instruction address to the appropriate boundary. */
|
||||
memaddr &= (info->mach == 16 ? ~1 : ~3);
|
||||
|
Loading…
Reference in New Issue
Block a user